/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package stud.cp.user.dbaccess;

import java.math.BigInteger;
import java.sql.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import org.apache.log4j.Logger;
import stud.cp.core.dbaccess.DAO;
import stud.cp.core.dbaccess.DAOException;
import stud.cp.user.valueobjects.Parameter;

/**
 * Класс, описывающий доступ к таблице PropertyValue
 *
 * @author Morfant
 */
public class ParametersDAO implements DAO<Parameter> {

    /**
     * Логгер.
     */
    private static Logger logger = Logger.getLogger("CPTNP");
    /**
     * Именая колонок промежуточной таблицы.
     */
    private static String[] parametersColumnNames = {
        "parameter_id",
        "object_id",
        "property_id",
        "value",
        "list_value_id",
        "date_value"
    };
    /**
     * Список названий колонок таблицы properties.
     */
    private static String[] propetyColumnName = {"property_id",
        "property_type_id",
        "property_group_id",
        "property_name",
        "property_type_def_id"};
    /**
     * Имя колонок таблицы property_types private static String[]
     * propertyTypeColumnName = {"property_type_id", "type_name"}; /** Имя
     * колонок таблицы propertyGroups
     */
    private static String[] propertyGroupsColumnName = {"property_group_id", "group_name"};
    /**
     * Имена колонок таблицы properlty_list_values
     */
    private static String[] propertyListValues = {"list_value_id", "list_value", "property_type_def_id"};
    private static String[] propertyTypes = {"property_type_id", "name"};
    /**
     * Коннект к базе данных.
     */
    private Connection connection = null;

    /**
     * Конструктор, который принимает connection к базе данных.
     *
     * @param connection Connection к базе данных.
     */
    ParametersDAO(Connection connection) {
        this.connection = connection;
    }

    /**
     * Запрос, позволяющий получить запись по id.
     *
     * @param id ID
     * @return Запрос.
     */
    private String getQueryForGetById(BigInteger id) {
        StringBuilder query = new StringBuilder();

        query.append("select pv.parameter_id,pv.object_id,pv.property_id,p.name as \"property_name\",");
        query.append("pv.value,pv.list_value_id,plv.value as \"list_value\",pg.name as \"group_name\",pt.property_type_id,pv.date_value \n");
        query.append("FROM parameters pv \n");
        query.append("inner join properties p on p.property_id=pv.property_id \n");
        query.append("inner join property_types pt on p.property_type_id=pt.property_type_id  \n");
        query.append("inner join property_groups pg on p.property_group_id=pg.property_group_id \n");
        query.append("left outer join list_values plv on plv.list_value_id=pv.list_value_id \n");
        query.append("where parameter_id=");
        query.append(id);

        return query.toString();
    }

    /**
     * Метод, позволяющий получить запись по её ID
     *
     * @param id ID
     * @return Данные записи.
     * @throws DAOException <p> Ошикба доступа к данным. </p>
     */
    @Override
    public Parameter getById(BigInteger id) throws DAOException {
        Parameter property_value = null;
        ResultSet set = null;
        PreparedStatement prestat = null;
        try {
            prestat = connection.prepareStatement(getQueryForGetById(id));
            set = prestat.executeQuery();
            if (set.next()) {
                property_value =
                        new Parameter(set.getBigDecimal(parametersColumnNames[0]).toBigInteger(),
                        set.getBigDecimal(parametersColumnNames[2]).toBigInteger(),
                        set.getString(propetyColumnName[3]),
                        set.getBigDecimal(parametersColumnNames[1]).toBigInteger(),
                        set.getBigDecimal(parametersColumnNames[4]) != null
                        ? set.getBigDecimal(parametersColumnNames[4]).toBigInteger() : null,
                        set.getString(propertyListValues[1]),
                        set.getString(propetyColumnName[3]),
                        set.getString(propertyGroupsColumnName[1]),
                        set.getBigDecimal(propertyTypes[0]).toBigInteger(),
                        set.getTimestamp(parametersColumnNames[5]));
            }
        } catch (SQLException ex) {
            logger.debug("DAO_propety", ex);
            throw new DAOException("Ошибка при создание данных..", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
        return property_value;
    }

    /**
     * Запрос на обновление записи в таблице.
     *
     * @param id ID
     * @param value Имя
     * @return Запрос.
     */
    private String getQueryForUpdate(BigInteger property_value_id, BigInteger property_list_value_id, String value) {
        StringBuilder query = new StringBuilder();
        query.append("UPDATE parameters \n");
        query.append("SET value='");
        query.append(value);
        query.append("' \n,list_value_id=");
        query.append(property_list_value_id);
        query.append(" \n");
        query.append("WHERE parameter_id=");
        query.append(property_value_id);
        return query.toString();
    }

    /**
     * Метод, отвечающий за обновление данных.
     *
     * @param entry Запись.
     * @throws DAOException Ошибка при обновление данных.
     */
    @Override
    public void update(Parameter entry) throws DAOException {
        PreparedStatement prestat = null;
        try {
            prestat = connection.prepareStatement(
                    getQueryForUpdate(
                    entry.getProperty_value_id(),
                    entry.getProperty_list_value_id(),
                    entry.getValue()));
            prestat.executeUpdate();
        } catch (SQLException ex) {
            logger.debug("DAO_propety_group", ex);
            throw new DAOException("Ошибка обновлени данных.", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
    }

    /**
     * Запрос на добавление новой записи в таблицу.
     *
     * @param id ID
     * @param name Имя
     * @return Запрос.
     */
    private String getQueryForInsert(BigInteger property_value_id, BigInteger object_id,
            BigInteger property_id, String value, BigInteger property_list_values_id, Date date) {
        StringBuilder query = new StringBuilder();
        query.append("insert into parameters(parameter_id,object_id,property_id,value,list_value_id,date_value) \n");
        query.append("VALUES(");
        query.append(property_value_id);
        query.append(",");
        query.append(object_id);
        query.append(",");
        query.append(property_id);
        query.append(",'");
        query.append(value);
        query.append("',");
        query.append(property_list_values_id);
        if(date!=null){
        DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        query.append(",CONVERT(datetime,'");
        query.append(formatter.format(date));
        query.append("'))");}
        else{
            query.append(",null)");
        } 
        return query.toString();
    }

    /**
     * Зарпос на получения следующего ID.
     *
     * @return Зарпос.
     */
    private String getQueryForSelectNextID() {
        StringBuilder query = new StringBuilder();
        query.append("SELECT property_values_seq.NEXTVAL from dual \n");
        return query.toString();
    }

    /**
     * Зарпос на получения максимального id из таблицы.
     *
     * @return Зарпос.
     */
    private String getQueryForSelectMaxId() {
        StringBuilder query = new StringBuilder();
        query.append("SELECT MAX(parameter_id) \n");
        query.append("FROM parameters");
        return query.toString();
    }

    /**
     * Метод, который создает новую запись в таблице.
     *
     * @param entry Запись.
     * @throws DAOException Ошибка создания новой записи.
     */
    @Override
    public BigInteger create(Parameter entry) throws DAOException {
        ResultSet set = null;
        PreparedStatement prestat = null;
        CallableStatement proc;
        try {
            proc = connection.prepareCall("{ call GetNextIdentity(?,?)}");
            proc.setString(1, "parameters");
            proc.registerOutParameter(2, java.sql.Types.BIGINT);

            proc.execute();

            BigInteger index = proc.getBigDecimal(2).toBigInteger();

            proc.close();
            prestat = connection.prepareStatement(getQueryForInsert(index,
                    entry.getObject_id(),
                    entry.getProperty_id(),
                    entry.getValue(),
                    entry.getProperty_list_value_id(),
                    entry.getData()));
            prestat.executeUpdate();
            return index;
        } catch (SQLException ex) {
            logger.debug("DAO_propety_group", ex);
            throw new DAOException("Ошибка при создание записи.", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
    }

    @Override
    public List<Parameter> getAll() throws DAOException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    /**
     * Зарпос на удаление из таблицы записи по id.
     *
     * @param id ID
     * @return Зарпос.
     */
    private String getQueryForDelete(BigInteger id) {
        StringBuilder query = new StringBuilder();
        query.append("DELETE FROM property_values \n");
        query.append("WHERE property_value_id=");
        query.append(id);
        return query.toString();
    }

    /**
     * Метод, позволяющий удалять данные по записи.
     *
     * @param id Запись.
     * @throws DAOException
     */
    @Override
    public void delete(BigInteger id) throws DAOException {
        PreparedStatement prestat = null;
        try {
            prestat = connection.prepareStatement(getQueryForDelete(id));
            prestat.executeUpdate();
        } catch (SQLException ex) {
            logger.debug("DAO_propety_group", ex);
            throw new DAOException("Ошибка удаления данных.", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
    }

    /**
     * Запрос, который позволяет выдернуть все значения свойств для
     * определенного оружия.
     *
     * @param object_id
     * @return
     */
    private String getQueryForAllPropertyValuesForObject(BigInteger object_id) {
        StringBuilder query = new StringBuilder();
        query.append("select pv.parameter_id,pv.object_id,pv.property_id,p.name as \"property_name\",");
        query.append("pv.value,pv.list_value_id,plv.value as \"list_value\",pg.name as \"group_name\",pt.property_type_id,pv.date_value \n");
        query.append("FROM parameters pv \n");
        query.append("inner join properties p on p.property_id=pv.property_id \n");
        query.append("inner join property_types pt on p.property_type_id=pt.property_type_id  \n");
        query.append("inner join property_groups pg on p.property_group_id=pg.property_group_id \n");
        query.append("left outer join list_values plv on plv.list_value_id=pv.list_value_id \n");
        query.append("where pv.object_id=");
        query.append(object_id);
        query.append("\n order by pg.name");
        return query.toString();
    }

    /**
     * Метод, который возращает набор значений свойств для оружия.
     *
     * @param object_id ID оружия.
     * @return Список значений свойств.
     */
    public List<Parameter> getPropertyValueForObject(BigInteger object_id) throws DAOException {
        List<Parameter> data_list = new LinkedList<Parameter>();
        ResultSet set = null;
        PreparedStatement prestat = null;
        try {
            prestat = connection.prepareStatement(getQueryForAllPropertyValuesForObject(object_id));
            set = prestat.executeQuery();
            while (set.next()) {
                data_list.add(new Parameter(
                        set.getBigDecimal(parametersColumnNames[0]).toBigInteger(),//property_value_id ID значения свойства
                        set.getBigDecimal(parametersColumnNames[2]).toBigInteger(),//property_id ID свойства
                        set.getString(parametersColumnNames[3]),//Значение
                        set.getBigDecimal(parametersColumnNames[1]).toBigInteger(),//ID оружия
                        //                        (set.getInt(propertyValuesColumnNames[4]) == 0) ? null : set.getInt(propertyValuesColumnNames[4]),
                        //ID по которому находиться списочное значение
                        set.getBigDecimal(parametersColumnNames[4]) != null
                        ? set.getBigDecimal(parametersColumnNames[4]).toBigInteger() : null,
                        set.getString(propertyListValues[1]),//Значие списочного свойства.
                        set.getString(propetyColumnName[3]),// property_name Имя свойства
                        set.getString(propertyGroupsColumnName[1]),//property_group_name Имя группы свойства.
                        set.getBigDecimal(propertyTypes[0]).toBigInteger(),
                        set.getTimestamp(parametersColumnNames[5])));//property_type_id Тип свойства
            }
        } catch (SQLException ex) {
            logger.debug("DAO_propeties", ex);
            throw new DAOException("Ошибка получения списка данных.", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
        return data_list;
    }

    /**
     * Запрос, позволяющий получить запись по id.
     *
     * @param id ID
     * @return Запрос.
     */
    private String getQueryForGetParameterByIdForObject(BigInteger propertyId, BigInteger objectId) {
        StringBuilder query = new StringBuilder();

        query.append("select pv.parameter_id,pv.object_id,pv.property_id,p.name as \"property_name\",");
        query.append("pv.value,pv.list_value_id,plv.value as \"list_value\",pg.name as \"group_name\",pt.property_type_id,pv.date_value \n");
        query.append("FROM parameters pv \n");
        query.append("inner join properties p on p.property_id=pv.property_id \n");
        query.append("inner join property_types pt on p.property_type_id=pt.property_type_id  \n");
        query.append("inner join property_groups pg on p.property_group_id=pg.property_group_id \n");
        query.append("left outer join list_values plv on plv.list_value_id=pv.list_value_id \n");
        query.append("where pv.property_id=");
        query.append(propertyId);
        query.append("\n and pv.object_id=");
        query.append(objectId);

        return query.toString();
    }

    /**
     * Метод, позволяющий получить запись по её ID
     *
     * @param id ID
     * @return Данные записи.
     * @throws DAOException <p> Ошикба доступа к данным. </p>
     */
    public Parameter getParameterByIdForObject(BigInteger propertyId, BigInteger objectId) throws DAOException {
        Parameter property_value = null;
        ResultSet set = null;
        PreparedStatement prestat = null;
        try {
            prestat = connection.prepareStatement(getQueryForGetParameterByIdForObject(propertyId, objectId));
            set = prestat.executeQuery();
            if (set.next()) {
                property_value =
                        new Parameter(
                        set.getBigDecimal(parametersColumnNames[0]).toBigInteger(),//property_value_id ID значения свойства
                        set.getBigDecimal(parametersColumnNames[2]).toBigInteger(),//property_id ID свойства
                        set.getString(parametersColumnNames[3]),//Значение
                        set.getBigDecimal(parametersColumnNames[1]).toBigInteger(),//ID оружия
                        //                        (set.getInt(propertyValuesColumnNames[4]) == 0) ? null : set.getInt(propertyValuesColumnNames[4]),
                        //ID по которому находиться списочное значение
                        set.getBigDecimal(parametersColumnNames[4]) != null
                        ? set.getBigDecimal(parametersColumnNames[4]).toBigInteger() : null,
                        set.getString(propertyListValues[1]),//Значие списочного свойства.
                        set.getString(propetyColumnName[3]),// property_name Имя свойства
                        set.getString(propertyGroupsColumnName[1]),//property_group_name Имя группы свойства.
                        set.getBigDecimal(propertyTypes[0]).toBigInteger(),
                        set.getTimestamp(parametersColumnNames[5]));
            }
        } catch (SQLException ex) {
            logger.debug("DAO_propety", ex);
            throw new DAOException("Ошибка при создание данных..", ex);
        } finally {
            if (prestat != null) {
                try {
                    prestat.close();
                } catch (SQLException ex) {
                    logger.debug("DAO_propety", ex);
                    throw new DAOException("Ошибка закрытия ResultSet`а.", ex);
                }
            }
        }
        return property_value;
    }
}
